//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include "windows.h"
#include <DevicePower.h>
#define SystemBasicInformation 0
#define SystemPerformanceInformation 2
#define SystemTimeInformation 3

typedef void * PVoid;
#define Li2Double(x) ((double)((x).HighPart) * 4.294967296E9 + (double)((x).LowPart))
typedef LONG (WINAPI *PROCNTQSI)(UINT,PVoid,ULONG,PULONG);
typedef struct
{
    DWORD dwUnknown1;
    ULONG uKeMaximumIncrement;
    ULONG uPageSize;
    ULONG uMmNumberOfPhysicalPages;
    ULONG uMmLowestPhysicalPage;
    ULONG uMmHighestPhysicalPage;
    ULONG uAllocationGranularity;
    PVoid pLowestUserAddress;
    PVoid pMmHighestUserAddress;
    ULONG uKeActiveProcessors;
    BYTE bKeNumberProcessors;
    BYTE bUnknown2;
    WORD wUnknown3;
} SYSTEM_BASIC_INFORMATION;

typedef struct
{
    LARGE_INTEGER liIdleTime;
    DWORD dwSpare[76];
} SYSTEM_PERFORMANCE_INFORMATION;

typedef struct
{
    LARGE_INTEGER liKeBootTime;
    LARGE_INTEGER liKeSystemTime;
    LARGE_INTEGER liExpTimeZoneBias;
    ULONG uCurrentTimeZoneId;
    DWORD dwReserved;
} SYSTEM_TIME_INFORMATION;

//varible
SYSTEM_PERFORMANCE_INFORMATION SysPerfInfo;
SYSTEM_TIME_INFORMATION SysTimeInfo;
SYSTEM_BASIC_INFORMATION SysBaseInfo;
LARGE_INTEGER liOldIdleTime;
LARGE_INTEGER liOldSystemTime;
PROCNTQSI NtQuerySystemInformation;
FILETIME u_old,u_new,s_old,s_new;//time counter
FILETIME dummy;

int  Profiler_Initialize()
{
    memset(&liOldIdleTime  ,   0, sizeof(LARGE_INTEGER));
    memset(&liOldSystemTime,   0, sizeof(LARGE_INTEGER));
    GetProcessTimes(GetCurrentProcess(),&dummy,&dummy,&s_old,&u_old);
    NtQuerySystemInformation = (PROCNTQSI)GetProcAddress(
    GetModuleHandleA("ntdll") , "NtQuerySystemInformation");
    if (!NtQuerySystemInformation)return -1;
    return 0;
}

INT64 FileTimeToQuadWork(PFILETIME pft)
{
    return (Int64ShllMod32(pft->dwHighDateTime,32) | pft->dwLowDateTime);
}

int Profiler_GetCpuUsage()
{
    long status = NtQuerySystemInformation(SystemTimeInformation,&SysTimeInfo,sizeof(SysTimeInfo),0);
    if (status != NO_ERROR)return -1;

    // get new CPU's idle time
    status = NtQuerySystemInformation(SystemPerformanceInformation,&SysPerfInfo,sizeof(SysPerfInfo),NULL);
    if (status != NO_ERROR)return -1;
    GetProcessTimes(GetCurrentProcess(),&dummy,&dummy,&s_new,&u_new);

    if (liOldIdleTime.QuadPart != 0) {
        double dbIdleTime = Li2Double(SysPerfInfo.liIdleTime) - Li2Double(liOldIdleTime);
        liOldIdleTime = SysPerfInfo.liIdleTime;//record for the next call
        liOldSystemTime = SysTimeInfo.liKeSystemTime;

        INT64 time=FileTimeToQuadWork(&u_new) - FileTimeToQuadWork(&u_old) +
                   FileTimeToQuadWork(&s_new) - FileTimeToQuadWork(&s_old);//the cpu time the process consumped from last call.

        u_old=u_new;
        s_old=s_new;

        return (UINT)(100.0 - 100.0 * dbIdleTime / (dbIdleTime + time));
    }
    else {
        liOldIdleTime = SysPerfInfo.liIdleTime;//record for the next call
        liOldSystemTime = SysTimeInfo.liKeSystemTime;
        return 0;
    }
}
